#include <stdio.h>
#include <stdlib.h>
#include "FileHeader.h"
#include "CentralDirectory.h"
#include "gTree.h"
#include "log/logger.h"

#define advanceToNextHeader {	fseek(testFile,offset,SEEK_SET);}

int signatureFile[] = {0x50, 0x4B, 0x03, 0x04};
int signatureCD[] = {0x50, 0x4B, 0x01, 0x02};
typedef FILE* GFile;
GFile testFile = 0;
int offset = 0;
FileHeader* cd = 0;

bool verifyHeader()
{
    advanceToNextHeader;
    int index = 0;
    bool equals = true;
    int current;
    while ((index < 4) && equals)
    {
        offset++;
        current = fgetc(testFile);
        equals = current == signatureFile[index++];
    }
    return equals;
}

int getNextValue(int numbers)
{
    int value = 0, increment = 1;
    while (numbers--)
    {
        int val = 0;
        val = fgetc(testFile);
        value += val*increment;
        increment *= 256;
        offset++;
    }
    return value;
}

void getNextText(char** str, int lenght)
{
    *str = new char[lenght + 1];
    for (int i = 0; i < lenght; i++)
    {
        char val = fgetc(testFile);
        (*str)[i] = val;
        offset++;
    }

    (*str)[lenght] = '\0';
}

void fillDataToHeader(FileHeader& fHeader)
{
    fHeader.version_ = getNextValue(2);
    fHeader.flags_ = getNextValue(2);
    fHeader.method_ = getNextValue(2);
    fHeader.time_ = getNextValue(2);
    fHeader.date_ = getNextValue(2);
    fHeader.crc32_ = getNextValue(4);
    fHeader.size_comp = getNextValue(4);
    fHeader.size_uncomp = getNextValue(4);
    fHeader.name_len = getNextValue(2);
    fHeader.extrafield_len = getNextValue(2);
}

CentralDirectory* readCentralDirectory()
{
    int versionMadeBy = getNextValue(2);
    FileHeader* headerCentral = new FileHeader();
    fillDataToHeader(*headerCentral);
    CentralDirectory* cd = new CentralDirectory(headerCentral);
    cd->versionMadeBy_ = versionMadeBy;
    cd->commentLenght_ = getNextValue(2);
    cd->diskStart_ = getNextValue(2);
    cd->intAttr_ = getNextValue(2);
    cd->extAttr_ = getNextValue(4);
    cd->offset_ = getNextValue(4);
    getNextText(&cd->header->name_, cd->header->name_len);
    getNextText(&cd->comments_, cd->commentLenght_);
    return cd;
}

void insertHeaderInTree(GTreeNode<string>* tree, int offset, GList<string>& headers)
{
    if (offset < headers.size())
    {
        string current = headers.get(offset);
        if (!tree->search(current))
            tree->add(current);
        insertHeaderInTree(tree->search(current), offset + 1, headers);
    }
}

char *substring(char *string, int position, int length)
{
    char *pointer;
    int c(0);

    pointer = new char[length + 1];

    if (pointer)
    {
        for (c = 0; c <= position - 1; c++)
            string++;

        for (c = 0; c < length; c++)
        {
            *(pointer + c) = *string;
            string++;
        }
    }

    *(pointer + c) = '\0';

    return pointer;
}

GList<string> split(char* headerName, char separator)
{
    GList<string> res;
    char* ptr = headerName;
    int lenght = 0;
    int ini = 0;
    char* aux = 0;

    while (*ptr)
    {
        if (*ptr == separator)
        {
            aux = substring(headerName, ini, lenght);
            //logger->log(INFO, "Aux : %s", aux);
            string str(aux);

            res.add(str);
            ini = lenght + 1;
            lenght = 0;
        }
        else
            lenght++;
        ptr++;
    }
    aux = substring(headerName, ini, lenght);
    res.add(aux);
    return res;
}

void fillZipTree(GTree<string>& zipTree)
{
    bool existHeaders;

    do
    {
        existHeaders = verifyHeader();
        if (existHeaders)
        {
            FileHeader* fileHeader = new FileHeader();
            fillDataToHeader(*fileHeader);
            char ** ptrname = &fileHeader->name_;
            getNextText(ptrname, fileHeader->name_len);

            INFO("%s", fileHeader->name_);

            GList<string> headers = split(fileHeader->name_, '/');

            GTreeNode<string>& parent = zipTree.getRoot();
            //insertHeaderInTree(zipTree, 0, parent.element_, headers);
            insertHeaderInTree(&parent, 0, headers);
            offset += fileHeader->extrafield_len + fileHeader->size_comp;
            delete fileHeader;
        }
    }
    while (existHeaders);
}

//int main()
//{
//
//    const char* filename = "fileA.zip";
//
//    testFile = fopen(filename, "r");
//    if (testFile)
//    {
//        
//        GTree<string> zipTree(filename);
//
//        fillZipTree(zipTree);
//
//        zipTree.traverse();
//
//        fclose(testFile);
//    } else
//        logger.log(DEBUG, "%s\n", "Can't read file");
//
//    return 0;
//}

